//定义一些事件名，这些事件名是固定的，不允许修改
const eventNames = [
  'API:UN_AUTH',
  'API:VALIDATE_ERROR',
  'USER:LOGOUT',
  'LOADING:START',
  'LOADING:FINISH',
  'LOADING:FAILED',
  'TAB_CLOSE_LAST'
] as const

type EventName = (typeof eventNames)[number]

interface I {
  //events属性是一个对象，键是事件名，值是一个 Set 对象，Set 对象中存放了所有监听该事件的订阅者的回调函数。也就是订阅者列表
  events: Record<EventName, Set<Function>>
  on: (event: EventName, callback: Function) => void
  emit: (event: EventName, ...args: any[]) => void
  once: (event: EventName, callback: Function) => void
  off: (event: EventName, callback: Function) => void
}
class Emitter implements I {
  //events属性是一个对象，键是事件名，值是一个 Set 对象，Set 对象中存放了所有监听该事件的订阅者的回调函数。也就是订阅者列表
  events: Record<EventName, Set<Function>>
  constructor() {
    this.events = {} as Record<EventName, Set<Function>>
  }
  //订阅事件
  on(event: EventName, callback: Function) {
    if (!this.events[event]) {
      this.events[event] = new Set()
    }
    this.events[event].add(callback)
  }
  //派发事件
  emit(event: EventName, ...args: any[]) {
    const callbacks = this.events[event]
    callbacks &&
      callbacks.forEach((fn) => {
        fn(...args)
      })
  }
  //移除监听
  off(event: EventName, callback: Function) {
    //找到该事件订阅者的集合加入新的订阅者，callbackList是应用数据类型，和this.events.get(event)指向同一个内存，同步修改
    const callbacks = this.events[event]
    callbacks && callbacks.delete(callback)
  }
  //监听一次事件
  once(event: EventName, callback: Function) {
    //通过该方法订阅的事件，只能被触发一次
    //不是直接调用callback，而是调用cb，cb调用callback，然后移除监听
    //不会直接把callback传给on，而是传给cb
    const cb = (...args: []) => {
      callback(...args)
      this.off(event, cb)
    }
    this.on(event, cb)
  }
}

export const emitter = new Emitter()
